﻿using PmSoft.Core;
using PmSoft.Core.Domain.Auth;
using PmSoft.Core.Extensions;
using System.Diagnostics.CodeAnalysis;

namespace PmSoft.Web.Abstractions.RealTime;

/// <summary>
/// 在线客户端管理器，负责管理连接到应用程序的在线客户端及其状态。
/// </summary>
public class OnlineClientManager : IOnlineClientManager
{
	/// <summary>
	/// 当客户端连接时触发的事件。
	/// </summary>
	public event EventHandler<OnlineClientEventArgs>? ClientConnected;

	/// <summary>
	/// 当客户端断开连接时触发的事件。
	/// </summary>
	public event EventHandler<OnlineClientEventArgs>? ClientDisconnected;

	/// <summary>
	/// 当用户连接时触发的事件。
	/// </summary>
	public event EventHandler<OnlineUserEventArgs>? UserConnected;

	/// <summary>
	/// 当用户断开连接时触发的事件。
	/// </summary>
	public event EventHandler<OnlineUserEventArgs>? UserDisconnected;

	/// <summary>
	/// 在线客户端存储，用于持久化客户端数据。
	/// </summary>
	protected IOnlineClientStore Store { get; }

	/// <summary>
	/// 初始化 <see cref="OnlineClientManager"/> 类的新实例。
	/// </summary>
	/// <param name="store">在线客户端存储实例。</param>
	public OnlineClientManager(IOnlineClientStore store)
	{
		Store = store;
	}

	/// <summary>
	/// 异步添加在线客户端，并触发相关事件。
	/// </summary>
	/// <param name="client">要添加的在线客户端对象。</param>
	/// <returns>表示异步操作的任务。</returns>
	public virtual async Task AddAsync(IOnlineClient client)
	{
		var user = client.ToUserIdentifierOrNull();

		if (user != null && !await this.IsOnlineAsync(user))
		{
			UserConnected.InvokeSafely(this, new OnlineUserEventArgs(user, client));
		}

		await Store.AddAsync(client);
		ClientConnected.InvokeSafely(this, new OnlineClientEventArgs(client));
	}

	/// <summary>
	/// 异步移除指定连接 ID 的客户端，并触发相关事件。
	/// </summary>
	/// <param name="connectionId">客户端的连接 ID。</param>
	/// <returns>如果客户端成功移除则返回 true，否则返回 false。</returns>
	public virtual async Task<bool> RemoveAsync(string connectionId)
	{
		IOnlineClient? client = null;
		bool result = await Store.TryRemoveAsync(connectionId, value => client = value);
		if (!result || client == null)
		{
			return false;
		}

		if (UserDisconnected != null)
		{
			var user = client.ToUserIdentifierOrNull();
			if (user != null && !await this.IsOnlineAsync(user))
			{
				UserDisconnected.InvokeSafely(this, new OnlineUserEventArgs(user, client));
			}
		}

		ClientDisconnected?.InvokeSafely(this, new OnlineClientEventArgs(client));
		return true;
	}

	/// <summary>
	/// 异步根据连接 ID 获取客户端，如果不存在则返回 null。
	/// </summary>
	/// <param name="connectionId">客户端的连接 ID。</param>
	/// <returns>找到的客户端对象，如果未找到则返回 null。</returns>
	public virtual async Task<IOnlineClient?> GetByConnectionIdOrNullAsync(string connectionId)
	{
		IOnlineClient? client = null;
		if (await Store.TryGetAsync(connectionId, value => client = value) && client != null)
		{
			return client;
		}

		return null;
	}

	/// <summary>
	/// 异步获取所有在线客户端的只读列表。
	/// </summary>
	/// <returns>包含所有在线客户端的只读列表。</returns>
	public Task<IReadOnlyList<IOnlineClient>> GetAllClientsAsync()
	{
		return Store.GetAllAsync();
	}

	/// <summary>
	/// 异步获取指定用户的所有在线客户端。
	/// </summary>
	/// <param name="user">用户标识，不能为 null。</param>
	/// <returns>与指定用户关联的所有在线客户端的只读列表。</returns>
	/// <exception cref="ArgumentNullException">如果 <paramref name="user"/> 为 null，则抛出。</exception>
	public virtual async Task<IReadOnlyList<IOnlineClient>> GetAllByUserIdAsync([NotNull]IUserIdentifier user)
	{
		Guard.NotNull(user, nameof(user));
		var userIdentifier = new UserIdentifier(user.TenantType, user.UserId);
		return await Store.GetAllByUserIdAsync(userIdentifier);
	}
}